﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Drawing;
using System.Windows.Forms;
using System.IO;

namespace RollDesktop
{
    #region 数据
    public enum WH_Codes : int
    {
        /// <summary>
        /// 底层键盘钩子
        /// </summary>
        WH_KEYBOARD_LL = 13,
        /// <summary>
        /// 底层鼠标钩子
        /// </summary>
        WH_MOUSE_LL = 14,
        /// <summary>
        /// 全部
        /// </summary>
        ALL
    }

    /// <summary>
    /// 鼠标钩子事件结构定义
    /// </summary>
    public struct MouseHookStruct
    {
        public Point p; //鼠标坐标 
        public IntPtr HWnd;//鼠标点击的控件的句柄 
        public uint wHitTestCode;// 
        public int dwExtraInfo;// 
    }

    /// <summary>
    /// 鼠标钩子事件结构定义
    /// </summary>
    public struct KeyboardbHookStruct
    {
        public int vkCode;
        public int scanCode;
        public int flags;
        public int time;
        public int dwExtraInfo;
    }
    #endregion

    public class WindowsHook
    {
        public WindowsHook()
        {
        }

        #region API
        /// <summary>
        /// 安装钩子
        /// </summary>
        /// <param name="idHook"></param>
        /// <param name="lpfn"></param>
        /// <param name="hInstance"></param>
        /// <param name="threadId"></param>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

        /// <summary>
        /// 卸载钩子
        /// </summary>
        /// <param name="idHook"></param>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        private static extern int UnhookWindowsHookEx(int idHook);

        /// <summary>
        /// 传递钩子
        /// </summary>
        /// <param name="idHook"></param>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
        #endregion

        #region 变量
        /// <summary>
        /// 键盘钩子句柄
        /// </summary>
        private int keyboard_pHook = 0;

        /// <summary>
        /// 鼠标钩子句柄
        /// </summary>
        private int mouse_pHook = 0;

        /// <summary>
        /// 钩子委托声明
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

        /// <summary>
        /// 鼠标委托
        /// </summary>
        HookProc mouseHookProcDelegate;

        /// <summary>
        /// 键盘委托
        /// </summary>
        HookProc keyboardHookProcDelegate;
        #endregion

        #region 私有方法
        /// <summary>
        /// 安装指定的钩子
        /// </summary>
        /// <param name="wh_codes"></param>
        /// <param name="hookProc"></param>
        /// <param name="errorMessage"></param>
        /// <param name="pHook"></param>
        private void InstallWindowsHook(WH_Codes wh_codes, HookProc hookProc, string errorMessage, ref int pHook)
        {
            pHook = SetWindowsHookEx((int)wh_codes, hookProc, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
            if (pHook == 0)
            {
                UnhookHook(wh_codes);
                throw new Exception(errorMessage);
            }
        }

        /// <summary>
        /// 卸载指定的钩子
        /// </summary>
        /// <param name="pHook"></param>
        private void UnInstallWindowsHook(int pHook)
        {
            if (pHook != 0)
            {
                UnhookWindowsHookEx(pHook);
            }
        }

        /// <summary>
        /// 键盘的事件
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            KeyboardbHookStruct data = (KeyboardbHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardbHookStruct));
            if (keyboard_pHook != 0)
            {
                switch ((Keys)data.vkCode)
                {
                    case Keys.LControlKey:
                    case Keys.LMenu:
                    case Keys.LWin:
                    case Keys.RWin:
                    case Keys.Delete:
                    case Keys.Escape:
                    case Keys.F4:
                    case Keys.Tab:
                        return 1;
                }
            }
            return CallNextHookEx(keyboard_pHook, nCode, wParam, lParam);
        }

        /// <summary>
        /// 鼠标的事件
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                return 1;
            }
            return CallNextHookEx(mouse_pHook, nCode, wParam, lParam);
        }
        #endregion

        /// <summary>
        /// 安装Hook
        /// </summary>
        public void InstallHook(WH_Codes wh_codes = WH_Codes.ALL)
        {
            switch (wh_codes)
            {
                case WH_Codes.WH_KEYBOARD_LL:
                    keyboardHookProcDelegate = KeyboardHookProc;
                    InstallWindowsHook(wh_codes, keyboardHookProcDelegate, "SetWindowsKeyboardHookEx failed.", ref keyboard_pHook);
                    break;
                case WH_Codes.WH_MOUSE_LL:
                    mouseHookProcDelegate = MouseHookProc;
                    InstallWindowsHook(wh_codes, mouseHookProcDelegate, "SetWindowsMouseHookEx failed.", ref mouse_pHook);
                    break;
                case WH_Codes.ALL:
                    keyboardHookProcDelegate = KeyboardHookProc;
                    InstallWindowsHook(WH_Codes.WH_KEYBOARD_LL, keyboardHookProcDelegate, "SetWindowsKeyboardHookEx failed.", ref keyboard_pHook);
                    mouseHookProcDelegate = MouseHookProc;
                    InstallWindowsHook(WH_Codes.WH_MOUSE_LL, mouseHookProcDelegate, "SetWindowsMouseHookEx failed.", ref mouse_pHook);
                    break;
            }
        }

        /// <summary>
        /// 卸载钩子
        /// </summary>
        public void UnhookHook(WH_Codes codes = WH_Codes.ALL)
        {
            switch (codes)
            {
                case WH_Codes.WH_KEYBOARD_LL:
                    UnInstallWindowsHook(keyboard_pHook);
                    break;
                case WH_Codes.WH_MOUSE_LL:
                    UnInstallWindowsHook(mouse_pHook);
                    break;
                case WH_Codes.ALL:
                    UnInstallWindowsHook(keyboard_pHook);
                    UnInstallWindowsHook(mouse_pHook);
                    break;
            }
        }
    }
}